1 package edu.jiangxin.apktoolbox.convert.protobuf.supervised;
2
3 import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
4 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
5 import org.fife.ui.rtextarea.RTextScrollPane;
6
7 import javax.swing.*;
8 import java.awt.*;
9 import java.io.File;
10 import java.io.IOException;
11 import java.io.PrintWriter;
12 import java.io.StringWriter;
13 import java.nio.file.Files;
14 import java.nio.file.Path;
15 import java.util.Objects;
16 import java.util.Optional;
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 public enum AppMain {
34 ;
35
36
37
38 @SuppressWarnings({ "WeakerAccess", "CallToSystemGetenv" })
39 public static final Path CACHE_DIRECTORY = Path.of(System.getenv("LOCALAPPDATA"), "ProtoToJson", "descriptorCache");
40
41
42
43 private static final int WIDTH = 700;
44
45
46
47 private static final int HEIGHT = 700;
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 @SuppressWarnings("OverlyBroadCatchBlock")
66 public static void main(final String[] args) {
67 try {
68 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
69
70
71 final DescriptorCache cache = AppMain.createCache();
72 if (cache.isEmpty()) {
73
74 AppMain.displayShortMessage(
75 "The descriptor cache is empty, could not load any descriptor, check the cache directory:\n"
76 + AppMain.CACHE_DIRECTORY.toAbsolutePath(), "Empty descriptor cache",
77 MessageType.ERROR);
78 return;
79 }
80 final ProtoToJson protoToJson = ProtoToJson.fromCache(cache);
81
82
83 final Optional<Path> protoFile = AppMain.chooseProtoFile(args);
84 if (protoFile.isEmpty()) {
85 return;
86 }
87
88
89 final String protoJson;
90
91 try {
92 protoJson = protoToJson.toJson(protoFile.orElseThrow());
93 } catch (final NoDescriptorFoundException e) {
94
95 AppMain.displayShortMessage(
96 "Unable to find a descriptor matching the given JSON message, check the cache directory:\n"
97 + AppMain.CACHE_DIRECTORY.toAbsolutePath(), "No matching descriptor found",
98 MessageType.ERROR);
99 return;
100 }
101
102
103 AppMain.displayJson(protoJson);
104 } catch (final Throwable t) {
105 final StringWriter sw = new StringWriter();
106 final PrintWriter pw = new PrintWriter(sw);
107 t.printStackTrace(pw);
108 AppMain.displayLongMessage(sw.toString(), "Error", MessageType.ERROR);
109 }
110 }
111
112
113
114
115
116
117
118
119
120
121
122 private static Optional<Path> chooseProtoFile(final String[] args) {
123 if (args != null && args.length > 0) {
124 return Optional.of(Path.of(args[0]));
125 }
126
127 @SuppressWarnings("AccessOfSystemProperties") final File workingDirectory =
128 new File(System.getProperty("user.dir"));
129 final JFileChooser fileChooser = new JFileChooser(workingDirectory);
130 fileChooser.setDialogTitle("Choose a protobuf message file");
131
132 if (fileChooser.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) {
133 return Optional.empty();
134 }
135
136 return Optional.of(fileChooser.getSelectedFile()
137 .toPath());
138 }
139
140 private static DescriptorCache createCache() throws IOException {
141 Files.createDirectories(AppMain.CACHE_DIRECTORY);
142 return DescriptorCache.fromDirectory(AppMain.CACHE_DIRECTORY);
143 }
144
145
146
147
148
149
150 private static void displayJson(final String json) {
151 Objects.requireNonNull(json);
152
153 AppMain.displayLongMessage(json, "Decoded JSON message", MessageType.PLAIN);
154 }
155
156
157
158
159
160
161
162
163 private static void displayLongMessage(final String message, final String title, final MessageType messageType) {
164 Objects.requireNonNull(message);
165 Objects.requireNonNull(title);
166 Objects.requireNonNull(messageType);
167
168 final RSyntaxTextArea textArea = new RSyntaxTextArea(message);
169 textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JSON);
170 textArea.setCodeFoldingEnabled(true);
171 textArea.setEditable(false);
172
173 final RTextScrollPane scrollPane = new RTextScrollPane(textArea);
174 scrollPane.setPreferredSize(new Dimension(AppMain.WIDTH, AppMain.HEIGHT));
175
176
177 JOptionPane.showMessageDialog(null, scrollPane, title, messageType.getCode());
178 }
179
180
181
182
183
184
185
186
187 @SuppressWarnings({ "SameParameterValue", "MagicConstant" })
188 private static void displayShortMessage(final String message, final String title, final MessageType messageType) {
189 Objects.requireNonNull(message);
190 Objects.requireNonNull(title);
191 Objects.requireNonNull(messageType);
192
193 JOptionPane.showMessageDialog(null, message, title, messageType.getCode());
194 }
195
196
197
198
199 private enum MessageType {
200
201
202
203 PLAIN(JOptionPane.PLAIN_MESSAGE),
204
205
206
207 ERROR(JOptionPane.ERROR_MESSAGE),
208
209
210
211 INFO(JOptionPane.INFORMATION_MESSAGE),
212
213
214
215 WARNING(JOptionPane.WARNING_MESSAGE),
216
217
218
219 QUESTION(JOptionPane.QUESTION_MESSAGE);
220
221
222
223
224 private final int code;
225
226
227
228
229
230
231 MessageType(final int code) {
232 this.code = code;
233 }
234
235
236
237
238
239
240 @SuppressWarnings("WeakerAccess")
241 public int getCode() {
242 return code;
243 }
244 }
245 }